# -*-coding:Utf-8 -* 
""" Event module
Contains all basics events types used in SZ.
Part of Core module.
"""

from time import time

class MASTER_EVENT(object):
	""" Master event """
	_singletone = {}
	
	def __new__(cls, layer = 0):
		if not layer in cls._singletone:
			cls._singletone[layer] = object.__new__(cls)
		return cls._singletone[layer]
		
	def __init__(self, layer = 0):
		if not hasattr(self,"_EV_PreviousEvent"):
			self._EV_PreviousEvent = self
			self._EV_NextEvent = None
			self._endloop_callback = []
	
	def __EV_Start__(self, *callback):
		for fu in callback:
			if callable(fu):
				self._endloop_callback.append(fu)
		if self._EV_NextEvent:
			ti = time()
			nextE = self._EV_NextEvent
			num = 0
			while nextE != self and nextE != None:
				nextE = nextE.__EV_Start__(num)
				num += 1
				if time()-ti > 1.0:
					print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAh !!!! "+str(num)+" Event in one frame !!!!")
					break
			self.__EV_Finished__(nextE,num)
		
	def __EV_Finished__(self, event, number):
		if self._EV_NextEvent == self:
			self._EV_PreviousEvent = self
			self._EV_NextEvent = None
		for fu in self._endloop_callback:
			fu(number)
		self._endloop_callback = []
		
	def addCallback(self,callback):
		if callable(callback):
			self._endloop_callback.append(callback)
	
	def freeAllEvents(self):
		if self._EV_NextEvent:
			ti = time()
			nextE = self._EV_NextEvent
			num = 0
			while nextE != self and nextE != None:
				tmp_evt = nextE._EV_NextEvent
				nextE.stop()
				nextE = tmp_evt
				num += 1
				if time()-ti > 1.0:
					print("Error on stoping event : function stop at "+str(num)+" event, at the event ",nextE)
					break
		
class BasicEvent(object):
	""" A Basic Event """
	
	layerDefault = 0
	
	def __init__(self):
		self._EV_TIME_lastupdate_ = 0.0
		self._EV_TIME_time_ = 0.0
		self.layer = BasicEvent.layerDefault
		self.active = False
		
	def __EV_update__(self, *param):
		if not self.update(*param):
			self._EV_TIME_lastupdate_ = time()
		
	def __bool__(self):
		return self.active 
	
	@classmethod
	def up(cls, ob, *param):
		if isinstance(ob, cls):
			ob.__EV_update__(*param)
		else:
			raise TypeError("First parametre must be an event.")
	
	def update(self,*param):
		self.stop()
	
	@property
	def EventLastUpdateTime(self):
		return self._EV_TIME_lastupdate_
		
	@property
	def EventTime(self):
		return self._EV_TIME_time_
		
	@property
	def TimeFromLastUpdate(self):
		if self._EV_TIME_lastupdate_ == 0.0:
			return time()
		return time()-self._EV_TIME_lastupdate_
			
	
	# Event Loop
	
	def __EV_Start__(self, number):
		finishEv = self.__EV_Finished__(number)
		self.__EV_update__()
		return finishEv
		
	def __EV_Finished__(self, number):
		return self._EV_NextEvent
	
	def activate(self):
		lanchtime = time()
		mEvt = MASTER_EVENT(self.layer)
		self._EV_TIME_time_ = lanchtime
		self._EV_PreviousEvent = mEvt._EV_PreviousEvent
		self._EV_PreviousEvent._EV_NextEvent = self
		mEvt._EV_PreviousEvent = self
		self._EV_NextEvent = mEvt
		self.active = True
		return self
		
	def stop(self):
		if not self.active:
			return
		self._EV_PreviousEvent._EV_NextEvent = self._EV_NextEvent
		self._EV_NextEvent._EV_PreviousEvent = self._EV_PreviousEvent
		self.active = False
		return self

class ClassEvent(type):
	
	layerDefault = BasicEvent.layerDefault
	
	def __init__(self,name, bases, attrs):
		self._EV_TIME_lastupdate_ = 0.0
		self._EV_TIME_time_ = 0.0
		self.layer = ClassEvent.layerDefault
		self.active = False
		type.__init__(self,name, bases, attrs)
		
	def __EV_update__(self, *param):
		self.update(*param)
		self._EV_TIME_lastupdate_ = time()
		
	def __bool__(self):
		return self.active
	
	def update(self,*param):
		self.stop()
	
	@property
	def EventLastUpdateTime(self):
		return self._EV_TIME_lastupdate_
		
	@property
	def EventTime(self):
		return self._EV_TIME_time_
		
	@property
	def TimeFromLastUpdate(self):
		if self._EV_TIME_lastupdate_ == 0.0:
			return time()
		return time()-self._EV_TIME_lastupdate_
	
	# Event Loop
	
	def __EV_Start__(self, number):
		finishEv = self.__EV_Finished__(number)
		self.__EV_update__()
		return finishEv
		
	def __EV_Finished__(self, number):
		return self._EV_NextEvent
	
	def activate(self):
		lanchtime = time()
		mEvt = MASTER_EVENT(self.layer)
		self._EV_TIME_time_ = lanchtime
		self._EV_PreviousEvent = mEvt._EV_PreviousEvent
		self._EV_PreviousEvent._EV_NextEvent = self
		mEvt._EV_PreviousEvent = self
		self._EV_NextEvent = mEvt
		self.active = True
		return self
		
	def stop(self):
		if not self.active:
			return
		self._EV_PreviousEvent._EV_NextEvent = self._EV_NextEvent
		self._EV_NextEvent._EV_PreviousEvent = self._EV_PreviousEvent
		self.active = False
		return self
		

class Event(BasicEvent):
	""" An Event """
	
	layerDefault = BasicEvent.layerDefault
	
	def __init__(self,func):
		self._EV_TIME_lastupdate_ = 0.0
		self._EV_TIME_time_ = 0.0
		self._EV_TIME_rate_ = 0.0
		self._EV_TIME_death_ = 0.0
		self.layer = Event.layerDefault
		self.upfunc = False
		if callable(func):
			self.upfunc = func
		self.active = False
		
	def setFunc(self,func):
		if callable(func):
			self.upfunc = func
	
	def update(self,*param):
		if self.upfunc:
			self.upfunc(self,*param)

	def __EV_update__(self, *param):
		self.update(*param)
		self._EV_TIME_lastupdate_ = time()
	
	# Event Loop
	
	def __EV_Start__(self, number):
		finishEv = self.__EV_Finished__(number)
		actualT = time()
		if self._EV_TIME_time_ == 0.0 or (self._EV_TIME_time_ > 0.0 and actualT >= self._EV_TIME_time_):
			self.__EV_update__()
			if type(self._EV_TIME_death_) == int:
				self._EV_TIME_death_ -= 1
			if self._EV_TIME_death_ != None and ( (type(self._EV_TIME_death_) == int and self._EV_TIME_death_ <= 0) or self._EV_TIME_death_ < actualT ):
				self.stop()
			elif self._EV_TIME_rate_ != 0.0:
				self._EV_TIME_time_ = actualT+self._EV_TIME_rate_
		return finishEv
	
	def activate(self, kamikaze = "gru"):
		if self.active == True:
			self.stop()
		if self._EV_TIME_rate_ == 0.0 and kamikaze == "gru":
			kamikaze = True
		else:
			kamikaze = False
		lanchtime = time()
		if self._EV_TIME_time_ < 0.0:
			lanchtime -= self._EV_TIME_time_
		if kamikaze:
			if type(kamikaze) == bool:
				self._EV_TIME_death_ = 0
			elif type(kamikaze) == int:
				self._EV_TIME_death_ = kamikaze
			elif type(kamikaze) == float:
				self._EV_TIME_death_ = lanchtime+kamikaze
		else:
			self._EV_TIME_death_ = None
			
		mEvt = MASTER_EVENT(self.layer)
		self._EV_TIME_time_ = lanchtime
		self._EV_PreviousEvent = mEvt._EV_PreviousEvent
		self._EV_PreviousEvent._EV_NextEvent = self
		mEvt._EV_PreviousEvent = self
		self._EV_NextEvent = mEvt
		self.active = True
		return self
		
	def delayEvent(self, time):
		if type(time) in (int,float):
			self._EV_TIME_time_ = float(-time)
		return self		
	def recurrentEvent(self, rate):
		if type(rate) in (int,float):
			self._EV_TIME_rate_ = float(rate)
		return self
		
	def stop(self):
		if not self.active:
			return
		self._EV_PreviousEvent._EV_NextEvent = self._EV_NextEvent
		self._EV_NextEvent._EV_PreviousEvent = self._EV_PreviousEvent
		self._EV_TIME_time_ = 0.0
		self._EV_TIME_death_ = 0.0
		self.active = False
		return self
	
	
